package com.googlecode.pwlodars.piteststat.database;

import java.sql.Timestamp;
import java.util.List;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;

import com.googlecode.pwlodars.piteststat.content.PackageInfo;
import com.googlecode.pwlodars.piteststat.content.PitestSingleResult;

public class PitResultDao {

	private JdbcTemplate jdbcTemplate;

	public PitResultDao(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	public List<PitestSingleResult> readResultsFromPackageAndChildren(int packageId){
		Timestamp latestRunDate=readLatestDate();
		
		return readResults(packageId, latestRunDate);
	}

	//TODO move packageId and latestRunDate to one Query obejct
	private List<PitestSingleResult> readResults(int packageId, Timestamp latestRunDate) {
		List<PitestSingleResult> result=readResultsFromOnlyOnePackagePackage(packageId,latestRunDate);
		List<PackageInfo> subPackages = readPackages(packageId);
		addResultsFromSubPackage(result, subPackages,latestRunDate);
		return result;
	}

	private Timestamp readLatestDate() {
		SqlRowSet rowSet = jdbcTemplate.queryForRowSet("select Max(runDate) from ClassInfo");
		rowSet.next();
		Timestamp timestamp = rowSet.getTimestamp("Max(runDate)");
		return timestamp;
	}

	private void addResultsFromSubPackage(List<PitestSingleResult> result, List<PackageInfo> subPackages, Timestamp latestRunDate) {
		for (PackageInfo packageInfo : subPackages) {
			List<PitestSingleResult> resultsFromSubPackage = readResults(packageInfo.getId(),latestRunDate);
			result.addAll(resultsFromSubPackage);
		}
	}
	
	public List<PitestSingleResult> readResultsFromOnlyOnePackage(int packageId){
		Timestamp latestRunDate=readLatestDate();
		return readResultsFromOnlyOnePackagePackage(packageId, latestRunDate);
	}
	
	private List<PitestSingleResult> readResultsFromOnlyOnePackagePackage(int packageId, Timestamp latestRunDate){
		String sql = "select id, className,testCoverage,mutationCoverage,runDate,packageId from ClassInfo where packageId=? and runDate=?";

		List<PitestSingleResult> results= this.jdbcTemplate.query(sql, new Object[] { packageId,latestRunDate }, new PitestrSingleResultMapper());
		return results;

	}
	
	public int readPackageId(String packageName){
		String sql = "select id from Package where name=?";

		return this.jdbcTemplate.queryForInt(sql, new Object[] { packageName });
	}
	
	public PackageInfo readPackageInfo(int packageId){
		String sql = "select id, name from Package where id=?";
		List<PackageInfo> query = this.jdbcTemplate. query(sql, new PackageMapper(), packageId );
		return returnFirstElement(query);
	}

	private PackageInfo returnFirstElement(List<PackageInfo> query) {
		if(query.size()>0){
			return query.get(0);
		}else{
			return null;
		}
	}

	public List<PackageInfo> readPackages(int parentId) {
		String sql = "select id, name from Package where parentId=?";

		List<PackageInfo> packages = this.jdbcTemplate.query(sql, new Object[] { parentId }, new PackageMapper());
		return packages;
	}

	public void saveResult(PitestSingleResult result) {
		savePackages(result);
		Integer parentId = readPackageId(result.getPackage());
		jdbcTemplate.update(
				"insert into ClassInfo (className,testCoverage,mutationCoverage,runDate,packageId) values (?,?,?,?,?)",
				result.getClassName(), 0, result.getMutationCoverage(), result.getRunDate(), parentId);

	}

	private void savePackages(PitestSingleResult result) {
		List<PackageInfo> packages = result.getPackage().getHierarchyPackages();

		for (PackageInfo packageInfo : packages) {
			saveOrUpdatePackage(packageInfo);
		}
	}

	private void saveOrUpdatePackage(PackageInfo packageInfo) {
		int numberOfGivenPackagesInDb = jdbcTemplate.queryForInt("select count(*) from Package where name=?",
				packageInfo.getName());

		if (numberOfGivenPackagesInDb == 0) {
			Integer parentId = readParentId(packageInfo);
			jdbcTemplate.update("insert into Package (parentId,name) values (?,?)", parentId, packageInfo.getName());
		}
	}

	private Integer readParentId(PackageInfo packageInfo) {
		if (packageInfo.hasParent()) {
			PackageInfo parentInfo = packageInfo.getParent();
			return readPackageId(parentInfo);
		}
		return 0;
	}

	private Integer readPackageId(PackageInfo packageInfo) {
		Integer parentId;
		parentId = jdbcTemplate.queryForInt("select id from Package where name=?", packageInfo.getName());
		return parentId;
	}

}
